//
// File:	EntityManager.cpp
// Author:	Thomas TISSOT-DUPONT
// Login:	<thomas.tissotdupont@free.fr>
//
// Create:	27/01/2010 at 17:39:56
// Purpose:	
//
#include <vector>
#include "Base.hpp"
#include "EntityManager.hpp"
#include "Trace.hpp"

//------------------------------------------------------------------
// Constructor / Destructor
//------------------------------------------------------------------
EntityManager::EntityManager()
	:	m_entities()
{
}

EntityManager::~EntityManager()
{
	Clear();
}

//------------------------------------------------------------------
// Get Entities List
//------------------------------------------------------------------
const tEntList &EntityManager::GetEntities() const
{
	return m_entities;
}

//------------------------------------------------------------------
// Entity By ID
//------------------------------------------------------------------
IEntity *EntityManager::GetEntityByID(unsigned long) const
{
	//UNDONE
	return NULL;
}

//------------------------------------------------------------------
// Entities by classname
//------------------------------------------------------------------
const tEntList EntityManager::GetEntitiesByClassName(const std::string &classname) const
{
	tEntList entitiesList;
	tEntList::const_iterator it = m_entities.begin();
	tEntList::const_iterator ite = m_entities.end();
	for (; it != ite; ++it)
	{
		if ((*it) && (*it)->GetClassname() == classname)
			entitiesList.push_back(*it);
	}
	return entitiesList;
}

//------------------------------------------------------------------
// Add Entity to List
//------------------------------------------------------------------
void EntityManager::AddEntity(IEntity *pEntity)
{
	tEntList::iterator it = m_entities.begin();
	tEntList::iterator ite = m_entities.end();
	for (; it != ite; ++it)
	{
		if (*it == pEntity)
			return;
	}
	m_entities.push_back(pEntity);
}

//------------------------------------------------------------------
// Update Pre Entities
//------------------------------------------------------------------
void EntityManager::UpdatePreEntities() const
{
	//Call every entity's Update() method
	tEntList::const_iterator it = m_entities.begin();
	tEntList::const_iterator ite = m_entities.end();
	for (; it != ite; ++it)
	{
		IEntity *pEnt = *it;
		if (pEnt != NULL)
		{
			pEnt->Update();
		}
	}
}

//------------------------------------------------------------------
// Update Post Entities
//------------------------------------------------------------------
void EntityManager::UpdatePostEntities() const
{
	//Now, we update the entities' physics and stuff
	tEntList::const_iterator it = m_entities.begin();
	tEntList::const_iterator ite = m_entities.end();
	for (; it != ite; ++it)
	{
		IEntity *pEnt = *it;
		if (pEnt != NULL)
		{
			//Following Entity
			if (pEnt->GetFollowingEntity() != NULL)
			{
				//Update Follow Position
				pEnt->SetX(pEnt->GetFollowingEntity()->GetX() + pEnt->GetFollowOffsetX());
				pEnt->SetY(pEnt->GetFollowingEntity()->GetY() + pEnt->GetFollowOffsetY());
				if (pEnt->GetFollowingEntity()->IsRemoved())
					pEnt->FollowEntity(NULL);
			}
			else
			{
				//Update Position
				pEnt->SetX(pEnt->GetX() + pEnt->GetVelocityX() * GlobalVariables::Global::Get().GetFrameTime());
				pEnt->SetY(pEnt->GetY() + pEnt->GetVelocityY() * GlobalVariables::Global::Get().GetFrameTime());
			}
			if (pEnt->GetAnimating())
				pEnt->GetAnimating()->Update();
		}
	}
}

//------------------------------------------------------------------
// Render Entities
//------------------------------------------------------------------
void EntityManager::RenderEntities() const
{
	//Sort the rendergroups by order of rendering
	std::vector<RenderGroup> renderGroups;
	renderGroups.push_back(RENDERGROUP_WORLD);
	renderGroups.push_back(RENDERGROUP_CHARACTERS);
	renderGroups.push_back(RENDERGROUP_ITEMS);
	renderGroups.push_back(RENDERGROUP_EFFECTS);
	renderGroups.push_back(RENDERGROUP_UNKNOWN); //TEMP ?

	//Render the entities related to each rendergroup
	//TODO: optimize it !
	std::vector<RenderGroup>::iterator rgIt = renderGroups.begin();
	std::vector<RenderGroup>::iterator rgIte = renderGroups.end();
	for (; rgIt != rgIte; ++rgIt)
	{
		tEntList::const_iterator entIt = m_entities.begin();
		tEntList::const_iterator entIte = m_entities.end();
		for (; entIt != entIte; ++entIt)
		{
			IEntity *pEnt = *entIt;
			if (pEnt != NULL && pEnt->GetRenderGroup() == *rgIt)
			{
				if (GlobalVariables::DisplayManager::Get().GetView()->IsRectInside(pEnt->GetCenterX(), pEnt->GetCenterY(), pEnt->GetWidth(), pEnt->GetHeight()))
				{
					pEnt->Render();
				}
			}
		}
	}
}

//------------------------------------------------------------------
// Remove Unused Entities
//------------------------------------------------------------------
void EntityManager::RemoveUnusedEntities()
{
	tEntList::iterator it = m_entities.begin();
	tEntList::iterator ite = m_entities.end();
	while (it != ite)
	{
		IEntity *pEnt = *it;
		if (!pEnt || pEnt->IsRemoved())
		{
			pEnt->OnDestroy();
			delete pEnt;
			it = m_entities.erase(it);
			continue;
		}
		++it;
	}
}

//------------------------------------------------------------------
// Clear
//------------------------------------------------------------------
void EntityManager::Clear()
{
	tEntList::iterator it = m_entities.begin();
	tEntList::iterator ite = m_entities.end();
	for (; it != ite; ++it)
	{
		delete (*it);
	}
	m_entities.clear();
}
